#include "Serial.h"
#include "Config.h"
#include <uart.h>

#define SERIAL_RX_BUFFER_SIZE (1<<5)
static unsigned char RxBuffer[SERIAL_RX_BUFFER_SIZE];
static int inIndex;
static int outIndex;

#define SERIAL_TX_BUFFER_SIZE (1<<9)
static unsigned char TxBuffer[SERIAL_TX_BUFFER_SIZE];
static int TXinIndex;
static int TXoutIndex;

/**********************************************************************
* Function:        void initEUSART (void)
* PreCondition:    None
* Input:		   None
* Output:		   None
* Side Effects:
* Overview:		  Initialization of USART
					1. Enable Transmitter and select High Baud Rate in TXSTA
					2. Select a value in SPGRB register to generate 9600 baud rate
					3. Enable Serial port in RCSTA register
					4. Enable continuous reception in RCSTA

***********************************************************************/
#ifdef USE_CRYSTAL
//const int BRG_VAlUE = 6;
const int BRG_VALUE = 25;
#else
//const int BRG_VALUE = 12; //Value for 38400
const int BRG_VALUE = 51; //Value for 9600 serial
#endif
void initEUSART (void)
{
          OpenUART1(UART_EN & UART_IDLE_CON & UART_ALTRX_ALTTX & UART_EN_WAKE & UART_DIS_LOOPBACK & UART_DIS_ABAUD & UART_NO_PAR_8BIT & UART_1STOPBIT,
                  UART_INT_TX & UART_TX_PIN_NORMAL & UART_TX_ENABLE & UART_INT_RX_CHAR,
                  BRG_VALUE);
          inIndex = 0;
          outIndex = 0;
          TXinIndex = 0;
          TXoutIndex = 0;
          EnableIntU1RX;
}

/**********************************************************************
* Function:        void PutString(unsigned char *mess)
* PreCondition:    None
* Input:		   Pointer to display message
* Output:		   None
* Side Effects:
* Overview:		   Sends the string to terminal till it finds NULL character.
***********************************************************************/
void PutString(const char *mess)
{
	while(*mess != '\0')
	{
  		Putchar(*mess++);
	}
}

/**********************************************************************
* Function:        unsigned char Getchar(void)
* PreCondition:    None
* Input:		   None
* Output:		   Return a byte received from UART
* Side Effects:
* Overview:		  Wait till a byte received from termianl and then returns the received data
***********************************************************************/
unsigned char GetcharHW(void)
{
    return ReadUART1();
}

unsigned char Getchar(void)
{
    unsigned char retVal = 0;
    if(HasData())
    {
        retVal = RxBuffer[outIndex];
        outIndex++;
        outIndex = outIndex & (SERIAL_RX_BUFFER_SIZE - 1);
    }
    return retVal;
}

int HasData(void)
{
    return inIndex != outIndex;
}

int HasTXData(void)
{
    return TXinIndex != TXoutIndex;
}

unsigned char GetTxChar(void)
{
    unsigned char retVal = 0;
    retVal = TxBuffer[TXoutIndex];
    TXoutIndex++;
    TXoutIndex = TXoutIndex & (SERIAL_TX_BUFFER_SIZE - 1);
    return retVal;
}
/**********************************************************************
* Function:        void Putchar (unsigned char send_data)
* PreCondition:    None
* Input:		   Byte to transmit
* Output:		   None
* Side Effects:
* Overview:		   Transmits a byte to terminal through UART.
***********************************************************************/
void Putchar (unsigned char send_data)
{
    DisableIntU1TX;

    TxBuffer[TXinIndex] = send_data;
    TXinIndex++;
    TXinIndex = TXinIndex & (SERIAL_TX_BUFFER_SIZE - 1);

    EnableIntU1TX;
}

/**********************************************************************
* Function:        void hex_ascii(unsigned char display_data)
* PreCondition:    None
* Input:		   HEX Value
* Output:		   None
* Side Effects:
* Overview:		 Convert Hex Value to ASCII and send to PC;
***********************************************************************/
void hex_ascii(unsigned char display_data)
{
    Putchar('0');
    Putchar('x');
	unsigned char temp;
	temp = ((display_data & 0xF0)>>4);
	if (temp <= 0x09)
		Putchar(temp+'0');
	else
		Putchar(temp+'0'+0x07);

	temp = display_data & 0x0F;
	if (temp <= 0x09)
		Putchar(temp+'0');
	else
		Putchar(temp+'0'+0x07);
        Putchar(' ');
//	Putchar('\r');
//	Putchar('\n');
}

void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
    unsigned char inboundChar = GetcharHW();
    RxBuffer[inIndex] = inboundChar;
    inIndex++;
    inIndex = inIndex & (SERIAL_RX_BUFFER_SIZE - 1);
    _U1RXIF = 0;
}

void __attribute((interrupt, no_auto_psv)) _U1TXInterrupt(void)
{
    if(HasTXData())
    {
       _U1TXIF = 0;
        WriteUART1(GetTxChar());
    }
    else
    {
        DisableIntU1TX;
    }
}